
///////////////////////////////////////////////////////////////////////////////
//
//  Copyright (c) 2009, Perry L Miller IV
//  All rights reserved.
//  BSD License: http://www.opensource.org/licenses/bsd-license.html
//
///////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////
//
//  The state container class.
//
///////////////////////////////////////////////////////////////////////////////

#include "SceneGraph/State/Container.h"

#include "Usul/Functions/NoThrow.h"

#include "boost/bind.hpp"

#include <stdexcept>

using namespace SceneGraph::State;


///////////////////////////////////////////////////////////////////////////////
//
//  Constructors.
//
///////////////////////////////////////////////////////////////////////////////

Container::Container() : BaseClass(),
  _mutex(),
  _ea(),
  _na()
{
}


///////////////////////////////////////////////////////////////////////////////
//
//  Destructor.
//
///////////////////////////////////////////////////////////////////////////////

Container::~Container()
{
  Usul::Functions::noThrow ( boost::bind ( &Container::_destroy, this ), "9991362270" );
}


///////////////////////////////////////////////////////////////////////////////
//
//  Destroy this instance.
//
///////////////////////////////////////////////////////////////////////////////

void Container::_destroy()
{
  _ea.clear();
  _na.clear();
}


///////////////////////////////////////////////////////////////////////////////
//
//  Add the attribute.
//
///////////////////////////////////////////////////////////////////////////////

void Container::add ( ExclusiveAttribute::RefPtr a )
{
  if ( true == a.valid() )
  {
    Guard guard ( _mutex );
    const std::type_info &type ( typeid ( *a ) );
    ExclusiveKey key ( &type );
    _ea[key] = a;
  }
}


///////////////////////////////////////////////////////////////////////////////
//
//  Add the attribute.
//
///////////////////////////////////////////////////////////////////////////////

void Container::add ( NonExclusiveAttribute::RefPtr a )
{
  if ( true == a.valid() )
  {
    Guard guard ( _mutex );
    const std::type_info &type ( typeid ( *a ) );
    NonExclusiveKey key ( &type, a->key() );
    _na[key] = a;
  }
}


///////////////////////////////////////////////////////////////////////////////
//
//  Remove the attribute.
//
///////////////////////////////////////////////////////////////////////////////

void Container::remove ( ExclusiveKey key )
{
  Guard guard ( _mutex );
  _ea.erase ( key );
}


///////////////////////////////////////////////////////////////////////////////
//
//  Remove the attribute.
//
///////////////////////////////////////////////////////////////////////////////

void Container::remove ( NonExclusiveKey key )
{
  Guard guard ( _mutex );
  _na.erase ( key );
}


///////////////////////////////////////////////////////////////////////////////
//
//  Helper function for visiting the state-container.
//
///////////////////////////////////////////////////////////////////////////////

namespace Helper
{
  template < class V, class S > inline void accept ( V &v, S &s )
  {
    typedef typename S::iterator Itr;
    typedef typename S::mapped_type Ptr;

    for ( Itr i = s.begin(); i != s.end(); ++i )
    {
      Ptr &ptr ( i->second );
      if ( true == ptr.valid() )
      {
        ptr->accept ( v );
      }
    }
  }
}


///////////////////////////////////////////////////////////////////////////////
//
//  Pass the visitor to the attributes.
//
///////////////////////////////////////////////////////////////////////////////

void Container::accept ( SceneGraph::Visitors::Visitor &v, VisitMode::Mode mode )
{
  if ( VisitMode::COPY_CHILDREN == mode )
  {
    ExclusiveAttributes ea;
    NonExclusiveAttributes na;
    {
      Guard guard ( _mutex );
      ea = _ea;
      na = _na;
    }
    Helper::accept ( v, ea );
    Helper::accept ( v, na );
  }
  else if ( VisitMode::LOCK_CHILDREN == mode )
  {
    Guard guard ( _mutex );
    Helper::accept ( v, _ea );
    Helper::accept ( v, _na );
  }
  else
  {
    throw std::runtime_error ( "Error 1935720002: visit mode not implemented" );
  }
}
